package org.bee.controller;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.bee.ResultTool;
import org.bee.enums.FileType;
import org.bee.enums.IsDelete;
import org.bee.enums.ResultCode;
import org.bee.exception.ExceptionUtils;
import org.bee.file.FileUtils;
import org.bee.id.UUIDUtils;
import org.bee.model.SysFile;
import org.bee.model.result.Result;
import org.bee.secuirty.annotation.ApiAuth;
import org.bee.secuirty.annotation.TokenIgnore;
import org.bee.secuirty.context.CurrentUser;
import org.bee.service.SysFileService;
import org.bee.transaction.TransUtils;
import org.bee.transaction.Transaction;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 文件上传
 */
@RestController
@RequestMapping("/file")
public class FileController {

    @Value("${fileSavePath}")
    private String rootDir;

    @Resource
    private SysFileService sysFileService;

    public static List<String>  imageType = Arrays.asList("jpg","jpeg","png","gif");
    public static List<String>  videosType = Arrays.asList("mp4","avi","flv");
    public static List<String>  docType = Arrays.asList("doc","docx");
    public static List<String>  excelType = Arrays.asList("xls","xlsx");
    public static List<String>  pptType = Arrays.asList("ppt","pptx");
    public static List<String>  pdfType = Arrays.asList("pdf");
    public static List<String>  txtType = Arrays.asList("txt");
    public static List<String>  audioType = Arrays.asList("mp3","wav");

    /**
     * 文件上传
     * @param file 上传的文件
     * @param request 请求
     * @return 上传结果
     */
    @PostMapping(path = "/upload")
    @ApiAuth(value = "file.upload",description = "文件上传")
    public Result uploadFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        Result result = ResultTool.success();
        String contextPath = request.getContextPath();

        String fileName = file.getOriginalFilename();
        long size = file.getSize();
        String fileType = null;
        if (null != fileName) {
            fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        }
        String fileContentType;
        Integer fileTypeCode;
        if(imageType.contains(fileType)){
            fileContentType = FileType.IMAGES.getRootPath();
            fileTypeCode = FileType.IMAGES.getCode();
        }else if(videosType.contains(fileType)){
            fileContentType = FileType.VIDEOS.getRootPath();
            fileTypeCode = FileType.VIDEOS.getCode();
        }else if(docType.contains(fileType)){
            fileContentType = FileType.DOC.getRootPath();
            fileTypeCode = FileType.DOC.getCode();
        }else if(excelType.contains(fileType)){
            fileContentType = FileType.EXCEL.getRootPath();
            fileTypeCode = FileType.EXCEL.getCode();
        }else if(pptType.contains(fileType)){
            fileContentType = FileType.PPT.getRootPath();
            fileTypeCode = FileType.PPT.getCode();
        }else if(pdfType.contains(fileType)){
            fileContentType = FileType.PDF.getRootPath();
            fileTypeCode = FileType.PDF.getCode();
        }else if(audioType.contains(fileType)){
            fileContentType = FileType.MUSIC.getRootPath();
            fileTypeCode = FileType.MUSIC.getCode();
        }else if(txtType.contains(fileType)){
            fileContentType = FileType.TXT.getRootPath();
            fileTypeCode = FileType.TXT.getCode();
        }else{
            fileContentType = FileType.OTHERS.getRootPath();
            fileTypeCode = FileType.OTHERS.getCode();
        }
        File dir = new File(rootDir + fileContentType);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        //给文件重新设置一个名字
        //后缀
        String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        String id = UUIDUtils.simpleUuid();
        String newFileName = id + suffix;
        Transaction trans = null;
        //5.复制操作
        try {
            String fileHash = FileUtils.getFileHash(file.getInputStream(), "SHA-256");
            SysFile sysFileCheck = sysFileService.selectByFileName(fileName, fileHash);
            if(null != sysFileCheck){
                //文件已存在则直接返回url
                String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                        + contextPath+"/"+"file/preview/"+sysFileCheck.getFilePath();
                result.setData(url);
                return result;
            }
            //创建这个新文件
            File newFile = new File(rootDir + fileContentType + File.separator + newFileName);
            file.transferTo(newFile);
            SysFile sysFile = new SysFile();
            sysFile.setId(id);
            sysFile.setFilePath(fileContentType + File.separator + newFileName);
            sysFile.setFileName(fileName);
            sysFile.setFileType(fileTypeCode);
            sysFile.setFileSuffix(fileType);
            sysFile.setFileSize((int) size);
            sysFile.setCreateTime(new Date());
            sysFile.setCreateUser(CurrentUser.getUser().getUserId());
            sysFile.setIsDeleted(IsDelete.FALSE.getCode());
            sysFile.setHashcode(fileHash);
            trans = TransUtils.getTrans();
            trans.begin();
            sysFileService.insert(sysFile);
            trans.commit();
            //返的外链url
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                    + contextPath+"/"+"file/preview/"+fileContentType + "/" + newFileName;
            result.setData(url);
            return result;
        } catch (IOException e) {
            TransUtils.rollback(trans);
            result = ResultTool.fail(ResultCode.FILE_UPLOAD_ERROR);
            result.setMsg(ExceptionUtils.getFullStackTrace(e));
            return ResultTool.fail();
        }
    }

    /**
     * 根据文件名返回文件
     * @param fileName 文件名
     * @return 文件资源
     */
    @TokenIgnore
    @GetMapping("download/{rootPath}/{fileName}")
    public ResponseEntity<org.springframework.core.io.Resource> downloadFile(@PathVariable String rootPath, @PathVariable String fileName) {
        return fileOut(rootPath, fileName, "attachment");
    }


    @TokenIgnore
    @GetMapping("preview/{rootPath}/{fileName}")
    public ResponseEntity<org.springframework.core.io.Resource> PreviewFile(@PathVariable String rootPath, @PathVariable String fileName) {
        return fileOut(rootPath, fileName, "inline");
    }


    private ResponseEntity<org.springframework.core.io.Resource> fileOut(String rootPath, String fileName,String disposition){
        File file = new File(rootDir + rootPath + File.separator + fileName);
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();

        String[] split = fileName.split("\\.");
        String fileId = split[0];
        SysFile sysFile = sysFileService.selectById(fileId);
        // 创建 MIME 类型映射
        MediaType mediaType = getMediaTypeForFileType(fileType);

        if (!file.exists()) {
            return ResponseEntity.notFound().build();
        }

        String realfileName = URLEncoder.encode(sysFile.getFileName(), StandardCharsets.UTF_8);
        org.springframework.core.io.Resource resource = new FileSystemResource(file);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, disposition+"; filename=\"" + realfileName + "\"")
                .contentType(mediaType)
                .body(resource);
    }

    private MediaType getMediaTypeForFileType(String fileType) {
        // 扩展 MIME 类型映射表
        return switch (fileType) {
            case "jpg", "jpeg" -> MediaType.IMAGE_JPEG;
            case "png" -> MediaType.IMAGE_PNG;
            case "gif" -> MediaType.IMAGE_GIF;
            case "mp4" -> MediaType.valueOf("video/mp4");
            case "avi" -> MediaType.valueOf("video/x-msvideo");
            case "flv" -> MediaType.valueOf("video/x-flv");
            case "pdf" -> MediaType.APPLICATION_PDF;
            case "doc" -> MediaType.valueOf("application/msword");
            case "docx" -> MediaType.valueOf("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            case "xls" -> MediaType.valueOf("application/vnd.ms-excel");
            case "xlsx" -> MediaType.valueOf("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            case "ppt" -> MediaType.valueOf("application/vnd.ms-powerpoint");
            case "pptx" ->
                    MediaType.valueOf("application/vnd.openxmlformats-officedocument.presentationml.presentation");
            case "mp3" -> MediaType.valueOf("audio/mpeg");
            case "wav" -> MediaType.valueOf("audio/wav");
            default -> MediaType.APPLICATION_OCTET_STREAM;
        };
    }
}
